package com.bbf.mathgen.util;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * 使用freemarker模板生成word文件
 * <p>只能生成doc文件；模板文件另存为xml文件，需要明确占位符不会被标签隔断。</p>
 * @author BBF
 */
public final class WordGeneratorUtil {
  private static final String UTF8 = "UTF-8";
  private static final Charset CHARSET_UTF8 = Charset.forName(UTF8);

  private WordGeneratorUtil() {
  }

  /**
   * 使用freemarker模板生成word文件
   * @param config freemarker配置，配置方法：
   *               <p>Configuration configuration = new Configuration();<br>
   *               configuration.setDefaultEncoding(BaseUtil.UTF8); <br>
   *               //模板文件放在resource根目录，可以自行调整<br>
   *               configuration.setClassForTemplateLoading(WordGeneratorUtil.class, "/");<br>
   *               </p>
   * @param dataMap 数据
   * @param templateName 模板名，需要全文件名xxx.ftl
   * @param file 要生成的文件名
   * @return 文件对象，如果失败抛出异常
   * @throws Exception 生成文件异常
   */
  public static File createDoc(final Configuration config,
                               final Map<?, ?> dataMap,
                               final String templateName,
                               final File file) throws Exception {

    //设置FreeMarker异常处理器
    config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
    config.setDefaultEncoding(UTF8);
    Template template = config.getTemplate(templateName, UTF8);
    //判断目标文件所在的目录是否存在
    final File parentFile = file.getParentFile();
    if (parentFile != null) {
      if (!parentFile.mkdirs() && !parentFile.isDirectory()) {
        throw new IOException("无法创建目录" + parentFile);
      }
    }
    if (file.exists()) {
      if (!file.delete()) {
        throw new IOException(file + "删除失败");
      }
    }
    // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
    try (FileOutputStream fs = new FileOutputStream(file);
         OutputStreamWriter osw = new OutputStreamWriter(fs, CHARSET_UTF8);
         Writer w = new BufferedWriter(osw)) {
      template.process(dataMap, w);
      w.flush();
      return file;
    }
  }

  /**
   * 使用freemarker模板生成word文件
   * @param config freemarker配置，配置方法：
   *               <p>Configuration configuration = new Configuration();<br>
   *               configuration.setDefaultEncoding(BaseUtil.UTF8); <br>
   *               //模板文件放在resource根目录，可以自行调整<br>
   *               configuration.setClassForTemplateLoading(WordGeneratorUtil.class, "/");<br>
   *               </p>
   * @param dataMap 数据
   * @param templateName 模板名，需要全文件名xxx.ftl
   * @param fileName 要生成的文件名
   * @return 文件对象，如果失败抛出异常
   * @throws Exception 生成文件异常
   */
  public static File createDoc(final Configuration config,
                               final Map<?, ?> dataMap,
                               final String templateName,
                               final String fileName) throws Exception {
    return createDoc(config, dataMap, templateName, new File(fileName));
  }
}
